package vip.lsjscl.flowboot.workflow.controller;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import vip.lsjscl.flowboot.common.BusinessException;
import vip.lsjscl.flowboot.common.ResponseData;
import vip.lsjscl.flowboot.workflow.entity.DKWorkflow;
import vip.lsjscl.flowboot.workflow.entity.DKWorkflowVersion;
import vip.lsjscl.flowboot.workflow.model.Edge;
import vip.lsjscl.flowboot.workflow.model.FlowDiagram;
import vip.lsjscl.flowboot.workflow.model.Node;
import vip.lsjscl.flowboot.workflow.model.dto.WorkflowCreateDTO;
import vip.lsjscl.flowboot.workflow.model.dto.WorkflowSaveDTO;
import vip.lsjscl.flowboot.workflow.model.vo.TransitionVO;
import vip.lsjscl.flowboot.workflow.service.DKWorkflowService;
import vip.lsjscl.flowboot.workflow.service.DKWorkflowVersionService;
import vip.lsjscl.flowboot.workflow.entity.DKActivity;
import vip.lsjscl.flowboot.workflow.entity.DKTransition;
import vip.lsjscl.flowboot.workflow.repository.DKActivityRepository;
import vip.lsjscl.flowboot.workflow.repository.DKTransitionRepository;

import java.util.*;

/**
 * 工作流定义控制器
 * 提供工作流的创建、更新、查询、发布等功能
 *
 * @author zhangxingju
 * @date 2025/02/13
 */
@RestController
@RequestMapping("/api/workflow")
@RequiredArgsConstructor
public class DKWorkflowController {
    private static final Logger log = LoggerFactory.getLogger(DKWorkflowController.class);

    private final DKWorkflowService workflowService;


    private final DKWorkflowVersionService workflowVersionService;

    private final DKActivityRepository activityRepository;

    private final DKTransitionRepository transitionRepository;

    /**
     * 创建新的工作流定义
     *
     * @param dto 工作流创建数据传输对象
     * @return 创建成功的工作流信息
     * @throws BusinessException 创建过程中的业务异常
     */
    @PostMapping("/create")
    public ResponseData createWorkflow(@RequestBody @Valid WorkflowCreateDTO dto) {
        DKWorkflow workflow = workflowService.createWorkflow(dto);
        return ResponseData.ok(workflow);
    }

    /**
     * 更新现有工作流定义
     *
     * @param request 包含更新数据的请求对象
     * @return 更新后的工作流信息
     */
    @PostMapping("/update")
    public ResponseData updateWorkflow(@RequestBody @Valid WorkflowSaveDTO request) {
        DKWorkflow saved = workflowService.saveWorkflow(request.getFlowData(), request.getId());
        return ResponseData.ok(saved);
    }

    /**
     * 获取所有工作流定义列表
     *
     * @return 工作流定义列表
     */
    @GetMapping("/list")
    public ResponseData getWorkflowList() {
        List<DKWorkflow> workflows = workflowVersionService.findAll();
        return ResponseData.ok(workflows);
    }

    /**
     * 根据ID获取工作流详情
     *
     * @param id 工作流ID
     * @return 工作流详细信息
     */
    @GetMapping("/detail")
    public ResponseData getWorkflowById(@RequestParam String id) {
        DKWorkflow workflow = workflowService.findById(id);
        return ResponseData.ok(workflow);
    }

    /**
     * 发布工作流
     *
     * @param id 工作流ID
     * @return 发布后的工作流版本信息
     */
    @PostMapping("/publish")
    public ResponseData publishWorkflow(@RequestParam String id) {
        // 先进行工作流完整性校验
        validateWorkflowCompleteness(id);
        DKWorkflowVersion version = workflowVersionService.publishWorkflow(id);
        return ResponseData.ok(version);
    }

    /**
     * 校验工作流的完整性
     * 1. 必须有开始和结束节点
     * 2. 从开始节点必须能到达结束节点
     * 3. 所有活动节点必须有入线和出线
     */
    private void validateWorkflowCompleteness(String id) {
        DKWorkflow workflow = workflowService.findById(id);
        FlowDiagram flowData = workflow.getFlowData();
        if (flowData == null || flowData.getNodes() == null || flowData.getEdges() == null) {
            throw new BusinessException("工作流数据不完整");
        }

        List<Node> nodes = flowData.getNodes();
        List<Edge> edges = flowData.getEdges();

        // 检查开始和结束节点
        Node startNode = null;
        Node endNode = null;
        Map<String, Node> nodeMap = new HashMap<>();
        for (Node node : nodes) {
            nodeMap.put(node.getId(), node);
            if ("start".equals(node.getType())) {
                startNode = node;
            }
            else if ("end".equals(node.getType())) {
                endNode = node;
            }
        }

        if (startNode == null || endNode == null) {
            throw new BusinessException("工作流必须包含开始和结束节点");
        }

        // 构建邻接表表示图
        Map<String, Set<String>> graph = new HashMap<>();
        Map<String, Integer> inDegree = new HashMap<>(); // 记录入度
        Map<String, Integer> outDegree = new HashMap<>(); // 记录出度

        // 初始化图
        for (Node node : nodes) {
            graph.put(node.getId(), new HashSet<>());
            inDegree.put(node.getId(), 0);
            outDegree.put(node.getId(), 0);
        }

        // 构建图的连接关系
        for (Edge edge : edges) {
            String source = edge.getSource();
            String target = edge.getTarget();
            graph.get(source).add(target);
            inDegree.merge(target, 1, Integer::sum);
            outDegree.merge(source, 1, Integer::sum);
        }

        // 检查从开始节点到结束节点的可达性
        Set<String> visited = new HashSet<>();
        validateReachability(startNode.getId(), endNode.getId(), graph, visited);
        if (!visited.contains(endNode.getId())) {
            throw new BusinessException("从开始节点无法到达结束节点");
        }

        // 检查所有活动节点的入度和出度
        for (Node node : nodes) {
            if ("activity".equals(node.getType())) {
                if (inDegree.get(node.getId()) == 0) {
                    throw new BusinessException("活动节点 [" + node.getData().getName() + "] 缺少入线");
                }
                if (outDegree.get(node.getId()) == 0) {
                    throw new BusinessException("活动节点 [" + node.getData().getName() + "] 缺少出线");
                }
            }
        }
    }

    /**
     * 使用DFS验证从起点到终点的可达性
     */
    private void validateReachability(String current, String end, Map<String, Set<String>> graph, Set<String> visited) {
        if (visited.contains(current)) {
            return;
        }
        visited.add(current);
        if (current.equals(end)) {
            return;
        }
        for (String next : graph.get(current)) {
            validateReachability(next, end, graph, visited);
        }
    }

    /**
     * 获取工作流的所有版本
     *
     * @param id 工作流ID
     * @return 工作流版本列表
     */
    @GetMapping("/versions")
    public ResponseData getWorkflowVersions(@RequestParam String id) {
        try {
            List<DKWorkflowVersion> versions = workflowVersionService.getWorkflowVersions(id);
            return ResponseData.ok(versions);
        }
        catch (Exception e) {
            log.error("获取工作流版本列表失败: {}", id, e);
            throw new BusinessException("获取工作流版本列表失败: " + e.getMessage());
        }
    }

    /**
     * 获取工作流特定版本
     *
     * @param businessId 业务id
     * @return 特定版本的工作流信息
     */
    @GetMapping("/version")
    public ResponseData getWorkflowVersion(@RequestParam String businessId) {
        DKWorkflowVersion workflowVersion = workflowVersionService.getWorkflowVersionByBusinessId(businessId);
        return ResponseData.ok(workflowVersion);
    }

    /**
     * 获取工作流特定版本
     *
     * @param versionId 流程版本id
     * @return 特定版本的工作流信息
     */
    @GetMapping("/versionById")
    public ResponseData getWorkflowVersionById(@RequestParam String versionId) {
        DKWorkflowVersion workflowVersion = workflowVersionService.findById(versionId);
        return ResponseData.ok(workflowVersion);
    }

    /**
     * 导出工作流定义
     *
     * @param id 工作流ID
     * @return 导出的工作流数据
     */
    @GetMapping("/export")
    public ResponseData exportWorkflow(@RequestParam String id) {
        DKWorkflow workflow = workflowService.findById(id);
        if (workflow == null) {
            throw new BusinessException("工作流不存在");
        }

        Map<String, Object> exportData = new HashMap<>();
        exportData.put("name", workflow.getName());
        exportData.put("code", workflow.getCode());
        exportData.put("flowData", workflow.getFlowData());

        return ResponseData.ok(exportData);
    }

    /**
     * 删除未发布的工作流
     *
     * @param id 工作流ID
     * @return 删除操作结果
     */
    @DeleteMapping("/delete")
    public ResponseData deleteWorkflow(@RequestParam String id) {
        workflowService.deleteWorkflow(id);
        return ResponseData.ok();
    }

    /**
     * 获取业务实例的活动数据
     *
     * @param businessId 业务ID
     * @return 活动数据列表
     */
    @GetMapping("/activities")
    public ResponseData getActivitiesByBusinessId(@RequestParam String businessId) {
        List<DKActivity> activities = activityRepository.findAllByBusinessId(businessId);
        return ResponseData.ok(activities);
    }

    /**
     * 获取业务实例的变迁数据
     *
     * @param businessId 业务ID
     * @return 变迁数据列表
     */
    @GetMapping("/transitions")
    public ResponseData getTransitionsByBusinessId(@RequestParam String businessId) {
        List<DKTransition> transitions = transitionRepository.findByBusinessId(businessId);
        List<TransitionVO> collect = transitions.stream().map(obj -> {
            TransitionVO transitionVO = new TransitionVO();
            BeanUtils.copyProperties(obj, transitionVO);
            transitionVO.setFromActivityId(obj.getFromActivity().getNodeId());
            transitionVO.setToActivityId(obj.getToActivity().getNodeId());
            transitionVO.setStatus(obj.getStatus().name());
            return transitionVO;
        }).toList();
        return ResponseData.ok(collect);
    }
}
